#include "Level.h"

Level::Level(void) : player(NULL), newQuest(NULL){
	init = false;
	//win = false;

	//player = new Character;

	enemyID = 0;
	numOfEnemy = 0;
	numOfSpawner = 0;

	spawnMob = false;

	msgBoard = new MessageBoard;

	our_font.init("Test.ttf", 30);
	char_font.init("Test.ttf", 20);

	QuestType = -1;
}

Level::~Level(void){
	for(vector<Platform *>::iterator itr = FloorList.begin(); itr != FloorList.end(); ++itr){
		delete (*itr);
	}
	FloorList.clear();

	for(vector<Platform *>::iterator itr = SpawnerList.begin(); itr != SpawnerList.end(); ++itr){
		delete (*itr);
	}
	SpawnerList.clear();

	for(vector<Platform *>::iterator itr = SpecialSpawnerList.begin(); itr != SpecialSpawnerList.end(); ++itr){
		delete (*itr);
	}
	SpecialSpawnerList.clear();

	for(vector<Ladder *>::iterator itr = LadderList.begin(); itr != LadderList.end(); ++itr){
		delete (*itr);
	}
	LadderList.clear();

	for( vector<PickUp *>::iterator itr = PickUpList.begin(); itr != PickUpList.end(); ++itr ){
		delete( *itr );
	}
	PickUpList.clear();

	for(vector<Enemy *>::iterator itr = EnemyList.begin(); itr != EnemyList.end(); ++itr){
		delete (*itr);
	}
	EnemyList.clear();

	if(player != NULL){
		delete player;
		player = NULL;
	}

	if(newQuest != NULL){
		delete newQuest;
		newQuest = NULL;
	}

	our_font.clean();
	char_font.clean();
}

void Level::CreateLadder(Vector3D position, int height, Ladder::LADDERTYPE type){
	Ladder *newLadder = new Ladder;
	newLadder->InitLadderHeight(position, height, type);
	LadderList.push_back(newLadder);
}

void Level::CreatePlatform(Vector3D position, int width, int height, Platform::PATHTYPE type, float r, float g, float b){
	Platform *newPlatform = new Platform;
	newPlatform->InitPlatformLength(position, width, height, type, r, g, b);

	if(type == Platform::PATHTYPE::AISPAWNPOINT){
		numOfSpawner++;
		SpawnerList.push_back(newPlatform);
	}else if(type == Platform::PATHTYPE::SPECIALSPAWN){
		SpecialSpawnerList.push_back(newPlatform);
	}else{
		FloorList.push_back(newPlatform);
	}
}

void Level::CreateEnemy(Vector3D position,Vector3D oOff){
	int rndNum = rand() % 2;
	Enemy *newEnemy;
	
	switch(rndNum){
		case 0:
			newEnemy = new MeleeEnemy;
			break;
		case 1:
			newEnemy = new RangeEnemy;
			break;
	}
	
	newEnemy->SetPosition(position);
	newEnemy->oOff = oOff;
	newEnemy->id = enemyID;
	newEnemy->LoadMessageBoard(msgBoard);
	newEnemy->LoadPlayerInfo(player);
	EnemyList.push_back( newEnemy );

	enemyID++;
	numOfEnemy++;
}

void Level::CreatePickUp(Vector3D position, Item::no itemNumber){
	PickUp *newPickUp = new PickUp;
	newPickUp->InitPickUp( position, itemNumber );
	newPickUp->SetOnGround(true);
	PickUpList.push_back( newPickUp );
}

BaseQuest::QUESTSTATUS Level::GetQuestStatus(void){
	return newQuest->GetQuestStatus();
}

void Level::InitLevel(Character *player, QUESTTYPE questType, int difficulty){
	this->player = player;
	this->player->SetDirection(Vector3D(0, 0, 0));

	this->QuestType = questType;

	if(questType == Level::PROTECT){
		newQuest = new ProtectQuest;
		ProtectQuest* temp = (ProtectQuest *) (newQuest);

		switch(difficulty){
			case BaseQuest::DIFFICULTY::EASY:
				temp->InitQuest(player, &EnemyList, &FloorList, &SpecialSpawnerList, 40);
				break;
			case BaseQuest::DIFFICULTY::NORMAL:
				temp->InitQuest(player, &EnemyList, &FloorList, &SpecialSpawnerList, 60);
				break;
			case BaseQuest::DIFFICULTY::HARD:
				temp->InitQuest(player, &EnemyList, &FloorList, &SpecialSpawnerList, 80);
				break;
			default:
				cout << "No such difficulty" << endl;
				break;
		}
	}else if(questType == Level::HUNT){
		newQuest = new HuntQuest;
		HuntQuest* temp = (HuntQuest *)(newQuest);

		switch(difficulty){
			case BaseQuest::DIFFICULTY::EASY:
				temp->InitQuest(player, &EnemyList, 5, 150);
				break;
			case BaseQuest::DIFFICULTY::NORMAL:
				temp->InitQuest(player, &EnemyList, 10, 120);
				break;
			case BaseQuest::DIFFICULTY::HARD:
				temp->InitQuest(player, &EnemyList, 15, 80);
				break;
			default:
				cout << "No such difficulty" << endl;
				break;
		}
	}else if(questType == Level::COLLECT){
		newQuest = new CollectQuest;
		CollectQuest* temp = (CollectQuest *)(newQuest);

		switch(difficulty){
			case BaseQuest::DIFFICULTY::EASY:
				temp->InitQuest(player, &FloorList, &SpawnerList, &PickUpList, 150);
				break;
			case BaseQuest::DIFFICULTY::NORMAL:
				temp->InitQuest(player, &FloorList, &SpawnerList, &PickUpList, 100);
				break;
			case BaseQuest::DIFFICULTY::HARD:
				temp->InitQuest(player, &FloorList, &SpawnerList, &PickUpList, 80);
				break;
			default:
				cout << "No such difficulty" << endl;
				break;
		}
	}

	newQuest->difficulty = difficulty;
}

void Level::RenderLevel(void){
	for(vector<Ladder *>::iterator itr = LadderList.begin(); itr != LadderList.end(); ++itr){
		(*itr)->DrawLadder();
	}
	
	for(vector<Platform *>::iterator itr = FloorList.begin(); itr != FloorList.end(); ++itr){
		(*itr)->DrawPlatform();
	}

	for(vector<Platform *>::iterator itr = SpawnerList.begin(); itr != SpawnerList.end(); ++itr){
		(*itr)->DrawPlatform();
	}

	for(vector<Platform *>::iterator itr = SpecialSpawnerList.begin(); itr != SpecialSpawnerList.end(); ++itr){
		(*itr)->DrawPlatform();
	}

	newQuest->RenderQuest();

	for( vector<Enemy *>::iterator itr = EnemyList.begin(); itr != EnemyList.end(); ++itr ){
		( *itr )->RenderObject();
	}

	for(vector<PickUp *>::iterator itr = PickUpList.begin(); itr != PickUpList.end(); ++itr){
		(*itr)->RenderObject();
	}

	if((player->GetLife() * 10) >= 20)
	{
		glColor3f(0.0f, 1.0f, 0.0f);
	}
	else if ((player->GetLife() * 10) >= 10 && (player->GetLife() * 10) <= 19)
	{
		glColor3f(1.0f, 1.0f, 0.0f);
	}
	else if ((player->GetLife() * 10) <= 9)
	{
		glColor3f(1.0f, 0.0f, 0.0f);
	}
	freetype::print(char_font, 20, 50, "Lives left: %2.0f", player->GetLife() * 10);
}

bool Level::UpdateLevel(float elapsed)
{
	this->FrameTime = elapsed;

	for(vector<Platform *>::iterator itr = FloorList.begin(); itr != FloorList.end(); ++itr){
		(*itr)->UpdatePlatform(player->hOff, Vector3D(), 0.0, elapsed);
	}

	if(numOfSpawner != 0 && numOfEnemy < MAXENEMY){
		if(!spawnMob){
			spawnMob = true;
			spawnTimer.StartTimer(0, 0, 5, 0);
		}else if(spawnMob && spawnTimer.CheckIfTimerEnd()){
			int rndNum = rand() % numOfSpawner;
			this->CreateEnemy(SpawnerList.at(rndNum)->GetPosition(), SpawnerList.at(rndNum)->GetoOff());
			//cout << numOfEnemy << endl;
			spawnMob = false;
		}
	}

	if(spawnTimer.CheckIfTimerRunning())
		spawnTimer.UpdateTimer();

	for(vector<Platform *>::iterator itr = SpawnerList.begin(); itr != SpawnerList.end(); ++itr){
		(*itr)->UpdatePlatform(player->hOff, Vector3D(), 0.0, elapsed);
	}

	for(vector<Platform *>::iterator itr = SpecialSpawnerList.begin(); itr != SpecialSpawnerList.end(); ++itr){
		(*itr)->UpdatePlatform(player->hOff, Vector3D(), 0.0, elapsed);
	}

	for(vector<PickUp *>::iterator itr = PickUpList.begin(); itr != PickUpList.end(); ++itr){
		(*itr)->UpdateObject(player->hOff, elapsed);

		if((*itr)->GetBoundingBox(Object::COLLISIONTYPE::FULLBODY).HitTest(player->GetBoundingBox(Object::COLLISIONTYPE::FULLBODY))){
			if((*itr)->GetItemType() != Item::type::QUEST){
				player->GetInventory()->AddItem(Item((*itr)->GetItemNumber()));

				delete (*itr);
				PickUpList.erase(itr);

				break;
			}
		}
	}

	for( vector<Enemy *>::iterator eItr = EnemyList.begin(); eItr != EnemyList.end(); ++eItr ){
		if((*eItr)->GetLife() <= 0.0f){
			(*eItr)->DropItemOnDeath(&PickUpList);
			
			numOfEnemy--;
			AchAddEnemiesKilled(1);

			delete (*eItr);
			EnemyList.erase(eItr);
			
			break;
		}

		(*eItr)->UpdateObject(player->hOff, elapsed);
		
		for(vector<Platform *>::iterator itr = FloorList.begin(); itr != FloorList.end(); ++itr){
			if((*itr)->CollisionWithPlatform((*eItr)->GetBoundingBox(Object::LEG)) == Platform::FLOOR){
				(*eItr)->SetOnGround(true);

				if((*itr)->CollisionWithPlatform((*eItr)->spaceCheck) != Platform::FLOOR){
					(*eItr)->WallHit(elapsed);
				}
				
				break;
			}else{
				(*eItr)->SetOnGround(false);
			}
		}
	
		for(vector<Platform *>::iterator itr = FloorList.begin(); itr != FloorList.end(); ++itr){
			if((*itr)->CollisionWithPlatform((*eItr)->GetBoundingBox(Object::FULLBODY)) == Platform::WALL 
				|| (*itr)->CollisionWithPlatform((*eItr)->GetBoundingBox(Object::LEG)) == Platform::WALL
				|| (*itr)->CollisionWithPlatform((*eItr)->GetBoundingBox(Object::HEAD)) == Platform::WALL){
				(*eItr)->WallHit(elapsed);
			}
		}
	}

	for(vector<Platform *>::iterator itr = FloorList.begin(); itr != FloorList.end(); ++itr){
		if((*itr)->CollisionWithPlatform(player->GetBoundingBox(Object::FULLBODY)) == Platform::WALL 
			|| (*itr)->CollisionWithPlatform(player->GetBoundingBox(Object::LEG)) == Platform::WALL
			|| (*itr)->CollisionWithPlatform(player->GetBoundingBox(Object::HEAD)) == Platform::WALL){
			player->SetDirection(Vector3D(player->GetDirection().x * -1, player->GetDirection().y, 0.0));
			player->WallHit(elapsed);
			player->Set_Character_Move_Deny( true );
			break;
		}else{
			player->Set_Character_Move_Deny( false );
		}
	}

	for(vector<Platform *>::iterator itr = FloorList.begin(); itr != FloorList.end(); ++itr){
		if((*itr)->CollisionWithPlatform(player->GetBoundingBox(Object::HEAD)) == Platform::CEILING){
			player->Move_Character_Jump_End();
			break;
		}

		if((*itr)->CollisionWithPlatform(player->GetBoundingBox(Object::LEG)) == Platform::FLOOR){
			player->SetOnGround(true);
			break;
		}else{
			player->SetOnGround(false);
		}
	}

	if(newQuest->UpdateQuest(player->hOff, elapsed)){
		return true;
	}else{
		return false;
	}
}